package com.li.io;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.PrintStream;
import java.util.regex.Pattern;

/**
 *  字节流分类  按照流是否直接与特定的地方(如文件、内存、键盘、设备等)相连，分为节点流和处理流两类。
 * 1、节点流 就是从或者向一个特定的地方（节点）进行读写数据
 * 常用的节点流：
 * FileInputStream 对文件进行读写
 * ByteArrayInputStream 对字节数组进行读写
 * PipeInputStream 对管道进行读写
 * 
 * 处理流这一块是典型的装饰模式
 * 2、处理流 是对一个已存在的流的连接和封装，通过所封装的流的功能调用实现数据读写
 * 常用的处理流：
 * BufferedInputStream 缓冲流，增加缓冲功能，避免频繁读写硬盘，加快效率
 * InputStreamReader 转换流，字节流转换为字符流
 * DataInputStream 数据流，提供将基础数据写入到节点当中，或者读取出来
 * printStream 打印流
 * ObjectInputStream 对象流，该类型的流可以把类作为一个整体进行存取
 *
 */
public class InputStreamDemo {
	public static void main(String[] args) throws Exception{
		//testFileInputStream();
		//testFileOutputStream();
		//testObjectOutputStream();
		//testObjectInputStream();
		//testBufferedInputStream();
		//testBufferedOutputStream();
		//testDataOutputStream();
		//testDataInputStream();
		//testByteArrayInputStream();
		//testByteArrayOutputStream();
		//testPrintStream();
	}
	/**
	 * 文件流主要对文件进行相应的操作
	 * 文件的读和文件的写操作
	 * 如果涉及到文字的读写操作，最好使用Reader和Writer,因为字节流是以一个字节单位的，
	 * java语言采用unicode编码，中文默认占用两个字节，所以字节流的方式可能会导致部分的乱码
	 * @throws Exception
	 */
	public static void testFileInputStream() throws Exception{
		//新建一个文件输入流，把文件的内容读到输入流中
		FileInputStream fi=new FileInputStream(new File("src/com/li/io/test.txt"));
		//设置一个每次从流中读取数据的字节缓存对象，每次读取的内容大小为该数据缓存对象的大小
		byte[] b=new byte[1024];
		//执行读取数据的操作，每次读取b大小的数据，若读取数据的返回标识不为-1，则没读取完，继续进行读取
		while(fi.read(b)!=-1){
			//将读取到的字节缓存对象，转化为String,进行输出显示，默认编码gbk
			System.out.print(new String(b));
		}
		fi.close();
	}

	public static void testFileOutputStream() throws Exception{
		//新建一个文件输入流，把文件的内容读到输入流中
		FileInputStream fi=new FileInputStream(new File("src/com/li/io/test.txt"));
		FileOutputStream fo=new FileOutputStream(new File("src/com/li/io/test2.txt"));
		//设置一个每次从流中读取数据的字节缓存对象，每次读取的内容大小为该数据缓存对象的大小
		byte[] b=new byte[64];
		//执行读取数据的操作，每次读取b大小的数据，若读取数据的返回标识不为-1，则没读取完，继续进行读取
		int tempCount=0;
		int allCount=0;
		while((tempCount=fi.read(b))!=-1){
			//将读取到的字节缓存对象，转化为String,进行输出显示，默认编码gbk
			//fo.write(b,0,tempCount);
			//allCount+=tempCount;
			fo.write(b);
		}
		fo.flush();
		fo.close();
		fi.close();
	}
	/**
	 * 对象流中，操作的对象必须实现了Serialable接口
	 * 对象流主要的功能是能把对象转化为流，然后进行传输
	 * @throws Exception
	 */
	public static void testObjectOutputStream() throws Exception{
		Student stu=new Student("li","23","男");
		ObjectOutputStream oo=new ObjectOutputStream(new FileOutputStream(new File("src/com/li/io/stu.txt")));
		oo.writeObject(stu);
		oo.flush();
		oo.close();
	}

	public static void testObjectInputStream() throws Exception{
		ObjectInputStream oi=new ObjectInputStream(new FileInputStream(new File("src/com/li/io/stu.txt")));
		Student stu=(Student)oi.readObject();
		System.out.println(stu);
		oi.close();
	}

	/**
	 * 缓冲流是处理流，经过缓冲流封装的字节流会具有比较好的性能和效率
	 * 缓冲流会设置一个固定大小的缓冲区，来对数据进行缓存，待缓冲区满后，再进行一次统一的数据读写
	 * 这样能够大大减少，对磁盘进行读写操作，磁盘的读写会经过磁盘寻道，这样一次会有一定的时间开销，次数
	 * 越多，效率也就慢慢地低了下来
	 * @throws Exception
	 */
	public static void testBufferedInputStream() throws Exception{
		BufferedInputStream bis=new BufferedInputStream(new FileInputStream(new File("src/com/li/io/test.txt")));
		byte[] b=new byte[1024];
		int tempLen=0;
		while((tempLen=bis.read(b))!=-1){
			System.out.print(new String(b));
		}
		bis.close();
	}

	public static void testBufferedOutputStream() throws Exception{
		BufferedOutputStream bos=new BufferedOutputStream(new FileOutputStream(new File("src/com/li/io/test2.txt")));
		BufferedInputStream bis=new BufferedInputStream(new FileInputStream(new File("src/com/li/io/test.txt")));
		byte[] b=new byte[1024];
		int tempLen=0;
		while((tempLen=bis.read(b))!=-1){
			bos.write(b);
		}
		bos.close();
		bis.close();
	}
	/**
	 * 对象输入输出流支持多Java基本类型数据进行读写操作，比如int，float，String等类型的数据
	 * 对象输入流，只能根据对象输出流写入的顺序和类型进行读取，读取的类型和顺序都得一致才能正确读取
	 * @throws Exception
	 */
	public static void testDataInputStream() throws Exception{
		DataInputStream di=new DataInputStream(new FileInputStream(new File("src/com/li/io/test.txt")));
		int s=di.readInt();
		int s2=di.readInt();
		System.out.println(s+"--"+s2);
		String a=di.readUTF();
		String a2=di.readUTF();
		System.out.println(a+"--"+a2);
		di.close();
	}

	public static void testDataOutputStream() throws Exception{
		DataOutputStream dos=new DataOutputStream(new FileOutputStream(new File("src/com/li/io/test.txt")));
		dos.writeInt(1);
		dos.writeInt(2);
		dos.writeUTF("哈哈");
		dos.writeUTF("呵呵");
		dos.flush();
		dos.close();
	}

	/**
	 * 字节数组输入输出流能够把数据暂时放在内存中，可以对字节数据进行读取操作，也可以把字节数组写入到内存中
	 * 一般吧字节数据输入输出流作为中间流进行相应的其他操作
	 * @throws Exception
	 */
	public static void testByteArrayInputStream() throws Exception{
		ByteArrayInputStream bis=new ByteArrayInputStream("你好吗".getBytes());
		byte[] b=new byte[1024];
		while(bis.read(b)!=-1){
			System.out.println(new String(b));
		}
		bis.close();
	}

	public static void testByteArrayOutputStream() throws Exception{
		ByteArrayOutputStream bos=new ByteArrayOutputStream();
		int a=127;
		int c=128;
		bos.write(a);
		bos.write(c);
		byte[] b=bos.toByteArray();
		//String b=bos.toString("gbk");
		for(int i=0;i<b.length;i++){
			System.out.println(b[i]);
		}
		bos.close();
	}

	/**
	 * 打印流，把数据打印到控制台中或者其他地方
	 * system.out是典型的打印流
	 */
	public static void testPrintStream(){
		PrintStream ps=System.out;
		ps.println("test");
	}
}

	

